package com.wangshouyu.mp.system.token;

import com.wangshouyu.mp.base.exception.MpException;
import com.wangshouyu.mp.base.request.MpClient;
import com.wangshouyu.mp.utils.GsonUtils;
import org.redisson.RedissonRedLock;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import java.util.concurrent.TimeUnit;

import static com.wangshouyu.mp.base.constant.Constant.LOCK;
import static com.wangshouyu.mp.base.constant.Constant.SUCCESS_CODE;

/**
 * @author 王守钰
 * @date 2020年12月19日 07:15
 * @description redisson accesstoken工具类
 */
public class AccessTokenRedissonHandler extends AccessTokenHandler{

    private AccessTokenRedissonHandler() {
    }

    /**
     * accessToken获取
     * @param client 微信客户端
     * @param appId 微信公众号id
     * @param secret 微信公众号秘钥
     * @param cachePrefix 缓存key
     * @param redissonClients Redisson客户端
     * @return accessToken
     */
    public static String accessToken(MpClient client,
                                          String appId,
                                          String secret,
                                          String cachePrefix,
                                          RedissonClient... redissonClients){
        if(null == client) {
            throw new MpException("mpClient is empty");
        }

        if(null == redissonClients) {
            throw new MpException("redissonClients is empty");
        }
        String key = cachePrefix;
        RBucket<String> bucket = redissonClients[0].getBucket(key);
        if(bucket.isExists()){
            AccessToken token = GsonUtils.fromJson((String)bucket.get(), AccessToken.class);
            return token.getAccessToken();
        }else{
            String lockKey = key + LOCK;
            int length = redissonClients.length;
            RLock[] locks = new RLock[length];
            for (int i = 0; i< length; i++){
                locks[i] = redissonClients[i].getLock(lockKey);
            }
            RedissonRedLock redLock = new RedissonRedLock(locks);
            boolean lockResult = false;
            try {
                lockResult = redLock.tryLock(500, 3000, TimeUnit.MILLISECONDS);
                if (lockResult) {
                    AccessToken accessToken = accessToken(client, appId, secret);
                    // accessToken不为空
                    if(null != accessToken
                            && SUCCESS_CODE.equals(accessToken.getErrCode())
                            && accessToken.getExpiresIn() > 0){
                        // 设置缓存
                        bucket.set(GsonUtils.toJson(accessToken),
                                accessToken.getExpiresIn() - 1000,
                                TimeUnit.SECONDS);
                        return accessToken.getAccessToken();
                    }

                }
            } catch (Exception e) {
                return accessToken(client, appId, secret, cachePrefix, redissonClients);
            } finally {
                if(lockResult){
                    redLock.unlock();
                }
            }
        }
        return null;
    }
}
